#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
和代码原始效果有　很大区别？？
　为啥？？？
"""

import cv2 as cv
import numpy as np


class CUTOUT(object):
    def __init__(self, stepName, config):
        self.config = config

    def cut_it(self):
        #要找的模板
        box =  cv.imread(self.config["template"])
        ##等待搜索的图
        box_in_sence =  cv.imread(self.config["sourceImg"])
        cv.imshow("template box", box)
        cv.imshow("sourceImg box_in_sence", box_in_sence)

        # 创建ORB特征检测器
        orb = cv.ORB_create()
        kp1, des1 = orb.detectAndCompute(box,None)
        kp2, des2 = orb.detectAndCompute(box_in_sence,None)

        # 暴力匹配
        # bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
        bf = cv.BFMatcher()

        # matches = bf.match(des1,des2)
        matches = bf.knnMatch(des1, des2, k=2)

        # 好的角点;
        goodMatches = []
        # 调整ratio
        for m, n in matches:
            if m.distance < 0.83 * n.distance:
                goodMatches.append([m])
        print("找到特征点的好点个数＝", len(goodMatches))
        if len(goodMatches)<4:
            print("失败！ 找到特征点的好点个数<4")
            return None

        # 筛选出好的描述角点子;   排序；
#        matches = sorted(matches, key = lambda x:x.distance)
#        for i in range(len(matches)):
            ##if (matches[i].distance < 0.46 * matches[-1].distance):  这个0.46参数越大，匹配点越多，准确性就越好，
#            if (matches[i].distance < 0.6 * matches[-1].distance):     ##最后那一个[-1]. matches
#                    goodMatches.append(matches[i])

#        result = cv.drawMatches(box, kp1, box_in_sence, kp2, goodMatches, None)


        result = cv.drawMatchesKnn(box, kp1, box_in_sence, kp2, goodMatches, None, flags=2)
        cv.imshow("goodMatches", result)   ##合成 拼接的 对照连线 图
        cv.imwrite("stepOut/goodMatches.jpg", result)

        # 好的角点　匹配的obj_pts#模板图；　scene_pts#含搜索目标的图;
        obj_pts, scene_pts = [], []

        # 单独保存 obj 和 scene 好的点位置
        for f in goodMatches:
            obj_pts.append(kp1[f[0].queryIdx].pt)   ##模板图
            scene_pts.append(kp2[f[0].trainIdx].pt)   ##含搜索目标的图

        #H, _= cv.findHomography(np.float32(obj_pts), np.float32(scene_pts), cv.RANSAC)
        ## 最关键！　Ｈ是　透视变换的　映射？？
        ##　getPerspectiveTransform 和　findHomography类似功能？
        #findHomography计算多个二维点对之间的最优单映射变换矩阵 H（3行x3列） ，使用最小均方误差或者RANSAC方法 。
        #至少需要4组对应的坐标，还得提出错误的点对。　RHO　RANSAC LMEDS
        ##正确的称为内点，错误的称为外点; reprojThreshold为阈值，当某一个匹配与估计的假设小于阈值时，则被认为是一个内点; ransacReprojThreshold
        #中心思想就是当内点占的比例较多时，那么很有可能已经找到了最优单映射变换矩阵;
        H, _ = cv.findHomography(np.float32(obj_pts), np.float32(scene_pts), cv.RHO)
        if H is  None:
            print("没能成功透视变换，实际图片和模板图差距太大了！参看stepOut/goodMatches.jpg")
            return None          #没能成功透视变换

        h, w = box.shape[0:2]
        #与原来模板图一样大小　的方框
        pts = np.float32([[0, 0], [0, h], [w, h], [w, 0]]).reshape(-1, 1, 2)

        #仿射变换后平行四边形的各边仍操持平行，透视变换结果允许是四边形，所以仿射变换是透视变换的子集；透视变换将2D矩阵图像变换成3D的空间显示效果
        ## warpPerspective 对图片 ； 和这　perspectiveTransform 对坐标点；　相似的???2D/3D功能。
        dst = cv.perspectiveTransform(pts, H).reshape(-1, 2)


        ##准备提取压力表小图，正规化。
        ##四个角点位置 顺序： 左上角，右上角，右下角那个点，左下角点。
        pts1 = dst
        ##目标输出图的　　对照的　　四个角点位置
        pts2 = np.float32([[0, 0], [0, h], [w, h], [w, 0]]).reshape(-1, 1, 2)

        ##四个角点　pts1输入图片的坐标。　　pts2输出目标图片的坐标。
        M = cv.getPerspectiveTransform(pts1,pts2)
        ##img_2源图片；　　M变换：目标的框宽＋高,输出图大小(300,200)
        outsmall = cv.warpPerspective(box_in_sence ,M,(w, h))
        ##模板匹配不恰好的， 变换出来的图片都很是异常的。
        cv.imshow("cutout-sourceImg", outsmall)
        cv.imwrite("stepOut/cutout-sourceImg.jpg", outsmall)

        # 4个框架点， result拼接图　就加上宽度的偏移量
        #for i in range(4):
        #    dst[i][0] += w
        #画 方框；　dst＝大图上：含搜索目标的图，上面的模板图对应四个角落点坐标点
        cv.polylines(box_in_sence, [np.int32(dst)], True, (0, 255, 0), 3, cv.LINE_AA)

        cv.imshow("orb-match", box_in_sence)
        cv.imwrite("stepOut/orb-match.jpg", box_in_sence)




